package com.xindacloud.sms.adapter.service.sms.impl;

import com.google.gson.Gson;
import com.xindacloud.sms.adapter.bo.HuoxinSmsResponseBO;
import com.xindacloud.sms.adapter.bo.HuoxinSubmitDataBO;
import com.xindacloud.sms.adapter.bo.SubmitMessageBO;
import com.xindacloud.sms.adapter.entity.SmsSubmissionRecord;
import com.xindacloud.sms.adapter.entity.SmsUserAllowOperator;
import com.xindacloud.sms.adapter.exception.ServiceException;
import com.xindacloud.sms.adapter.service.business.ISmsSubmissionRecordService;
import com.xindacloud.sms.adapter.service.business.ISmsUserAllowOperatorService;
import com.xindacloud.sms.adapter.service.business.ISmsUserService;
import com.xindacloud.sms.adapter.service.sms.ISubmitMessageService;
import com.xindacloud.sms.adapter.utils.*;
import com.xindacloud.sms.adapter.vo.SubmitMessageResultVO;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA
 * User: 张家喻
 * Date: 2020/8/3
 * Time: 10:57
 * Description:
 */
@Slf4j
@Service("huoxinSubmitMessageService")
public class HuoxinSubmitMessageServiceImpl implements ISubmitMessageService<SubmitMessageBO, SubmitMessageResultVO> {

    @Autowired
    private ISmsUserAllowOperatorService smsUserAllowOperatorService;

    @Autowired
    private ISmsSubmissionRecordService smsSubmissionRecordService;

    @Autowired
    private ISmsUserService smsUserService;

    @Override
    public SubmitMessageResultVO submitMessage(SubmitMessageBO submitMessageBO) {
        final String huoxinUserId = submitMessageBO.getApiKey();
        final String apiKey = submitMessageBO.getApiSecret();
        final String apiUrl = submitMessageBO.getApiUrl();
        final String callBackUrl = submitMessageBO.getCallBackUrl();
        final String content = submitMessageBO.getMessageBody();
        final Integer userId = submitMessageBO.getUserId();
        final String taskId = submitMessageBO.getTaskId();
        final String recipient = submitMessageBO.getRecipient();
        final String senderId = submitMessageBO.getSenderId();
        final Integer messageCount = submitMessageBO.getMessageCount();
        final String countryCode = submitMessageBO.getCountryCode();
        final String countryPrefix = submitMessageBO.getCountryPrefix();
        final BigDecimal costPrice = submitMessageBO.getCostPrice();
        final String agentId = submitMessageBO.getAgentId();
//        final String nonce = UUID.randomUUID().toString();
//        final String timestamp = DateHelp.localDateTime2Str(LocalDateTime.now());

        if (!CommonUtils.isMobile(recipient)) {
            throw new ServiceException("无效的手机号码.", UnionResultHelp.StatusEnum.ParamsFail.code());
        }

        try {
            long timeMillis = System.currentTimeMillis();
            String sign = HMACMD5Util.encryption(huoxinUserId + String.valueOf(timeMillis) + apiKey);
            String msgContent = "【" + senderId +  "】" + content;

            HuoxinSmsResponseBO<HuoxinSubmitDataBO> huoxinSmsResponseBO = WebClient
                    .create(apiUrl.concat("/api/sms/send"))
                    .post()
                    .uri(uriBuilder -> uriBuilder
                            .queryParam("userid", huoxinUserId)
                            .queryParam("ts", timeMillis)
                            .queryParam("sign", sign)
                            .queryParam("mobile", recipient.substring(2))
                            .queryParam("msgcontent", msgContent)
                            .build())
                    .retrieve()
                    .onStatus(HttpStatus::is4xxClientError, clientResponse ->
                            Mono.error(new ServiceException("火信云通道提交短信异常.", clientResponse.statusCode().value()))
                    )
                    .onStatus(HttpStatus::is5xxServerError, clientResponse ->
                            Mono.error(new ServiceException("火信云通道提交短信异常.", clientResponse.statusCode().value()))
                    )
                    .bodyToMono(new ParameterizedTypeReference<HuoxinSmsResponseBO<HuoxinSubmitDataBO>>(){})
                    .block();
            log.info("火信云通道发送返回结果:{}", new Gson().toJson(huoxinSmsResponseBO));

            String uuid = Objects.isNull(huoxinSmsResponseBO.getData()) ? "" : huoxinSmsResponseBO.getData().getTaskid();
            Integer code = Integer.valueOf(huoxinSmsResponseBO.getCode());

            //根据返回的network查询当前号码所属国家的售价
            final String network = getNetwork(recipient);
            final SmsUserAllowOperator userAllowOperator = smsUserAllowOperatorService
                    .queryOneMaxPriceOrderByDesc(userId, countryCode, countryPrefix, network);
            if (Objects.isNull(userAllowOperator)) {
                throw new ServiceException("未同步运营商价格,或未找到:" + network + "服务通道.", UnionResultHelp.StatusEnum.InnerError.code());
            }

            final BigDecimal calcMessagePrice = MessageTypeHelp.calcMessagePrice(userAllowOperator.getPrice(), messageCount);
            final boolean uuIdNotEmpty = StringUtils.isNotEmpty(uuid);

            // 更新短信状态信息
            final SmsSubmissionRecord submissionRecord = SmsSubmissionRecord.builder()
                    .agentId(uuIdNotEmpty ? agentId : "")
                    .free(uuIdNotEmpty ? calcMessagePrice : BigDecimal.ZERO)
                    .costPrice(uuIdNotEmpty ? costPrice : BigDecimal.ZERO)
                    .prefix(countryPrefix)
                    .countryCode(countryCode)
                    .messageId(uuid)
                    .messageCount(messageCount)
                    .errorText(code == 0 ? "" : huoxinSmsResponseBO.getMsg())
                    .network(network)
                    .submitStatusCode(code)
                    .finalStatus(uuIdNotEmpty ? StatusEum.SUBMITTED.desc : StatusEum.FAILED.desc)
                    .sendTo(recipient)
                    .taskId(taskId)
                    .userId(userId)
                    .minus(true)
                    .build();
            smsSubmissionRecordService.updateSmsSubmissionRecordFor(submissionRecord);

            if (uuIdNotEmpty) {
                //更新用户账户信息
                smsUserService.updateSmsPrice(userId, calcMessagePrice);
            }

            return SubmitMessageResultVO.builder()
                    .submitStatus(code)
                    .network(network)
                    .messageId(uuid)
                    .errorText(huoxinSmsResponseBO.getMsg())
                    .messageCount(messageCount)
                    .build();

        } catch (Exception e) {
            log.error("火信云发送短信异常:{}", e.getMessage(), e);
            throw new ServiceException("短信发送异常".concat(e.getMessage()), UnionResultHelp.StatusEnum.BadRequest.code());
        }
    }


    /**
     * 根据电话号码获取运营商网络编码
     * @param recipient
     * @return
     */
    private String getNetwork(String recipient) {

        final String carrierEn = PhoneUtil.getCarrier(recipient.substring(2), 86);
        String networkCode = "";
        switch (carrierEn) {
            case "China Mobile":
                networkCode = "46000";
                break;
            case "China Unicom":
                networkCode = "46001";
                break;
            case "China Telecom":
                networkCode = "46003";
                break;
            default:
                break;
        }
        return networkCode;
    }
}
